#!/usr/bin/perl
use warnings;
use strict;
use Fcntl qw( :flock );
use POSIX qw( strftime );

#******************************************************************************
# File: 
#		perl.pl
# Recipe: 7.18
#		Locking a File
# Version:
#		0.1
# Author:
#   	Yubei Zhu
# Mail:
#		yubeizhu@gmail.com
# Created at:
#   	2012-08-22  
# Last Update:
#   	2012-08-22
# License: 
#		GPLv3	
#******************************************************************************

# Common lock flag used in flock 
my %hLockFlag = ( "LOCK_SH" => LOCK_SH, # 1: Require a share lock
                  "LOCk_EX" => LOCK_EX, # 2: Require a exclusive lock
                  "LOCK_NB" => LOCK_NB, # 4: Reuqire a lock with non-block mode    
				  "LOCK_UN" => LOCK_UN  # 8: Release the current lock
);

# Print the value of each flag
for my $sFlag ( keys %hLockFlag ) {
	print "Lock ype: ", $sFlag," , ",$hLockFlag{ $sFlag  },"\n";
}

open my $fhIN, "+<", "test.log" or die "Can't open file: $!";


my $sStatus = UnlockFile( $fhIN );
print "Status: $sStatus\n";

$sStatus = LockFile( $fhIN,"EX"  );
print "Status: $sStatus\n";

# Lock released
$sStatus =  UnlockFile( $fhIN );
print "Status: $sStatus\n";

$sStatus = LockFile( $fhIN, "Share" );
print "Status: $sStatus\n";

# Lock released
$sStatus =  UnlockFile( $fhIN );
print "Status: $sStatus\n";

# Lock released
$sStatus =  UnlockFile( $fhIN );
print "Status: $sStatus\n";


close( $fhIN ) or die "Can't close file:$!";

sub LockFile
#*****************************************************************************
# PURPOSE: 
# USAGE:      
# PASSED ARGS:  
# RETURN ARGS: 
# $sError - Fail Error Message
#*****************************************************************************
{	
	my ( $fhHandle, $sLockType, $sBlock ) = @_;
	my ( $sResult ) = 0;
	
	# Check fileHandle and lockType
	return 0 if not $fhHandle or ref($fhHandle) ne "GLOB";
	return 0 if not $sLockType or $sLockType !~ /[ES]/i;

	# We use block-mode when advisory lock is found default  
	$sBlock =  defined $sBlock ? $sBlock : 1;
	
	# Hard code here, default lock type
	# Other processes require SH lock can also read this file simultaneously
	# Exclusive lock will be suspended when the file is under a share lock
	$sLockType = LOCK_SH;
	
	# Other processes require lock will be suspened
	$sLockType = LOCK_EX 	if $sLockType =~ /^E/i; 
	
	# Block current process when the file is locked by a 
	# adversary Lock
	$sLockType |= LOCK_NB 	if not $sBlock; 
	eval{
		$sResult = flock( $fhHandle, $sLockType );
	};
	return $@ ? 0 : $sResult ;
}

sub UnlockFile
#*****************************************************************************
# PURPOSE: 
# USAGE:      
# PASSED ARGS:  
# RETURN ARGS: 
# $sError - Fail Error Message
#*****************************************************************************
{
	my ( $fhHandle ) = shift ;
	my ( $sResult ) = 0;
	return 0 if not $fhHandle or ref($fhHandle) ne "GLOB";
	eval{
		# Unlock the file
		$sResult = flock( $fhHandle, LOCK_UN );
	};
    return $@ ? 0 : $sResult;
}




